package jmine.tec.scheduling.web.pages.task;

import images.ImageResources;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

import jmine.tec.hydra.scheduling.HydraSpecificationScheduledAction;
import jmine.tec.report.impl.table.CellValueResolver;
import jmine.tec.report.impl.table.ReportTableBuilder;
import jmine.tec.scheduling.Action;
import jmine.tec.scheduling.dao.ScheduledTaskDAO;
import jmine.tec.scheduling.domain.ScheduledTask;
import jmine.tec.scheduling.quartz.ManualScheduledJobExecutionContext;
import jmine.tec.web.wicket.component.command.button.ButtonCommand;
import jmine.tec.web.wicket.component.command.button.SearchCommand;
import jmine.tec.web.wicket.component.command.img.AbstractAjaxImageCommand;
import jmine.tec.web.wicket.component.command.img.EditCommand;
import jmine.tec.web.wicket.component.command.img.ImageCommand;
import jmine.tec.web.wicket.component.command.img.ViewCommand;
import jmine.tec.web.wicket.component.command.img.ViewCommandHandler;
import jmine.tec.web.wicket.pages.form.CrudPage;
import jmine.tec.web.wicket.pages.form.FormType;
import jmine.tec.web.wicket.spring.SpringBeanReference;

import org.apache.wicket.Page;
import org.apache.wicket.PageParameters;
import org.apache.wicket.ResourceReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.DropDownChoice;

import bancosys.tec.exception.MessageCreator;
import bancosys.tec.persist.dao.BaseDAOFactory;
import bancosys.tec.rtm.impl.RtmController;
import bancosys.tec.security.annotation.Secure;
import bancosys.tec.security.authorization.UrlPermission;
import bancosys.tec.utils.date.Date;
import bancosys.tec.utils.date.WallClock;

/**
 * Lists scheduled tasks
 * 
 * @author lundberg
 */
@Secure(id = "URL_LIST_SCHEDULED_TASK", permissionType = UrlPermission.class)
public class ListScheduledTaskPage extends CrudPage<ScheduledTask> implements ViewCommandHandler {

    private static final int INIT_HEIGHT_MODAL = 200;

    private static final int INIT_WIDTH_MODAL = 700;

    private ModalWindow modalWindow;

    /**
     * {@inheritDoc}
     */
    public Page createNewPage() {
        return new EditScheduledTaskPage(this.getClass(), new PageParameters());
    }

    /**
     * {@inheritDoc}
     */
    public List<ScheduledTask> search(BaseDAOFactory daoFactory) {
        ScheduledTaskDAO dao = daoFactory.getDAOByClass(ScheduledTaskDAO.class);
        ScheduledTask model = this.getModel();
        return dao.findLikeByMnemonicDescriptionActive(model.getMnemonic(), model.getDescription(), model.getActive());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void fillSearchEntity(ScheduledTask entity) {
        entity.setActive(true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Page createFormPage(ScheduledTask entity, FormType formType) {
        return new EditScheduledTaskPage(this.getClass(), new PageParameters(), entity, formType);
    }

    /**
     * @return list of booleans
     */
    private List<Boolean> listBoolean() {
        List<Boolean> result = new ArrayList<Boolean>();
        result.add(null);
        result.add(true);
        result.add(false);
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void addSearchFields(WebMarkupContainer container) {
        container.add(this.createTextField("mnemonic", this.getModel(), "mnemonic"));
        container.add(this.createTextField("description", this.getModel(), "description"));
        DropDownChoice<Boolean> activeDropDown = this.createDropDown("active", this.listBoolean());
        activeDropDown.setRequired(false);
        activeDropDown.setNullValid(true);
        container.add(activeDropDown);

        this.modalWindow = new ModalWindow("modalRun");

        this.modalWindow.setInitialWidth(INIT_WIDTH_MODAL);
        this.modalWindow.setInitialHeight(INIT_HEIGHT_MODAL);
        container.add(this.modalWindow);

    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void addResultTableColumns(ReportTableBuilder<ScheduledTask> table) {
        table.addStringColumn("mnemonic", "Mnemônico", "mnemonic");
        table.addStringColumn("description", "Descrição", "description");
        table.addStringColumn("cron", "Cron expression", "cron");
        table.addStringColumn("active", "Ativa", new CellValueResolver<ScheduledTask>() {
            public Object resolveCellValue(ScheduledTask task) {
                return task.getActive() ? "true" : "false";
            }
        });
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected MessageCreator getHelpTextCreator() {
        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<ImageCommand> getTableCommands(ScheduledTask entity) {
        List<ImageCommand> commands = new ArrayList<ImageCommand>();
        commands.add(new RunCommand(entity, this));
        commands.add(new ViewCommand(this));
        commands.add(new EditCommand(this));
        return commands;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean shouldIncludeTableCommands() {
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected List<ButtonCommand> getPageCommands() {
        List<ButtonCommand> commands = new ArrayList<ButtonCommand>();
        commands.add(new SearchCommand());
        return commands;
    }

    /**
     * Commando para pegar a data e rodar a task
     * 
     * @author Willian Gigliotti
     */
    public class RunCommand extends AbstractAjaxImageCommand {

        private final ScheduledTask entity;

        private final ListScheduledTaskPage page;

        /**
         * Contrutor
         * 
         * @param entity task
         * @param page Page
         */
        public RunCommand(ScheduledTask entity, ListScheduledTaskPage page) {
            this.entity = entity;
            this.page = page;
        }

        /**
         * {@inheritDoc}
         */
        public ResourceReference getImage() {
            return new ResourceReference(ImageResources.class, "ic_seta.gif");
        }

        /**
         * {@inheritDoc}
         */
        public String getMarkupIdPrefix() {
            return "run";
        }

        /**
         * {@inheritDoc}
         */
        @Override
        protected Page execute(AjaxRequestTarget target, Serializable commandParam) {
            this.page.modalRun(target, this.entity);
            return null;
        }

    }

    /**
     * Cria o modal com a task
     * 
     * @param target ajax
     * @param entity task
     */
    public void modalRun(AjaxRequestTarget target, ScheduledTask entity) {
        this.modalWindow.setContent(new ModalPanelExecutarTask(this.modalWindow, entity, this));
        this.modalWindow.show(target);
    }

    /**
     * Roda uma Task <br>
     * Se a task for uma {@link HydraSpecificationScheduledAction}, ele seta a data passada como parametro para rodar a tarefa
     * 
     * @param task task
     * @param data data
     * @param target ajax
     */
    public void runTask(ScheduledTask task, final Date data, AjaxRequestTarget target) {
        // this.info(WebPagesMessages.EXECUTAR_TASK.create(task.getMnemonic()));
        target.addComponent(this.get("feedback"));

        SpringBeanReference<RtmController> rtmControllerRef = SpringBeanReference.forName("rtmController");
        SpringBeanReference<Action> actionRef = SpringBeanReference.forName(task.getAction());

        final Action action = actionRef.get();

        // XXX (renan) : implementação deve ser mais generica...
        if (HydraSpecificationScheduledAction.class.isAssignableFrom(action.getClass())) {
            HydraSpecificationScheduledAction act = (HydraSpecificationScheduledAction) action;

            act.setClock(new WallClock() {
                @Override
                public Date currentDate() {
                    return data;
                }
            });
        }

        try {
            rtmControllerRef.get().executeTransacted(new Callable<Action>() {
                public Action call() throws Exception {
                    action.execute(new ManualScheduledJobExecutionContext());
                    return action;
                }
            });

        } catch (Exception e) {
            rtmControllerRef.get().monitor(e);
        }
    }
}
